{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Refrigeration cycle Analysis - OOP\n",
    "\n",
    "* expressions to code directly\n",
    "\n",
    "\n",
    "* Object-oriented programming\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1 Modeling and Simulation Methods of Engineering Systems\n",
    "\n",
    "### 1.1 Introduction\n",
    "\n",
    "**R Sinha, Christiaan J. J. Paredis. etc. Modeling and Simulation Methods for Design of Engineering Systems. Transactions of the ASME[J]. 2001.03(1):84-91**\n",
    "\n",
    "Modeling and simulation enables designers to test whether design specifications are met by using `virtual` rather than `physical`\n",
    "experiments. \n",
    "\n",
    "The use of virtual prototypes significantly shortens the design cycle and reduces the cost of design. It further provides\n",
    "the designer with immediate feedback on design decisions which,in turn, promises a more comprehensive exploration of design\n",
    "alternatives and a better performing final design. \n",
    "\n",
    "Simulation is particularly important for the design of multidisciplinary systems in which components in different disciplines (mechanical, electrical,embedded control, etc.) are tightly coupled to achieve optimal system performance.\n",
    "\n",
    "Several general-purpose simulation modeling paradigms and languages have been developed. \n",
    "\n",
    "They can be classified according to the following criteria:\n",
    "\n",
    "* `graph-based` versus `language-based` paradigms, \n",
    "\n",
    "* `procedural` versus `declarative` models, \n",
    "\n",
    "* `multi-domain` versus `single-domain` models, \n",
    "\n",
    "* `continuous` versus `discrete` models, and \n",
    "\n",
    "* `functional` versus `object-oriented` paradigms.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 Modeling and Simulation Software\n",
    "\n",
    "**Process Simulation**\n",
    " \n",
    "* **[Apros](http://www.apros.fi/en/)** : the commercial dynamic simulation software for modelling and simulation of various types of power plant processes, energy systems and networks including automation. Developed by **Fortum and VTT** Technical Research Centre of **Finland** Ltd since 1986.\n",
    "\n",
    "* **[Aspen Plus](https://www.aspentech.com/en/products/engineering/aspen-plus):**  The software package designed to allow a user to build a process model and then simulate the model without tedious calculations. The Chemical Industry's Leading Process Simulation Software. AspenTech,**USA**\n",
    "\n",
    "**Electronic Circuit Simulator** \n",
    "\n",
    "* **[Multisim](http://www.ni.com/zh-cn/shop/electronic-test-instrumentation/application-software-for-electronic-test-and-instrumentation-category/what-is-multisim.html)**: the industry standard **SPICE** simulation and circuit design software for analog, digital, and power electronics in education and research.National Instruments,**USA**\n",
    "        \n",
    "**Thermal Engineering**\n",
    "\n",
    "* **Ebsilon Professional**:the simulation system for thermodynamic cycle processes that is used for plant design and optimization,STEAG SYSTEM TECHNOLOGIES,**Germany**. \n",
    "\n",
    "* **Thermoflow**: the thermal engineering software for the power and cogeneration industries,Thermoflow Inc.**USA**\n",
    "\n",
    "\n",
    "![](./img/vcr/buildingexample.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.3 The Language for Modeling of Physical Systems\n",
    "\n",
    "**Modelica** https://www.modelica.org/\n",
    "  * https://github.com/PySEE/SimVCCE\n",
    "\n",
    "\n",
    "**MATLAB**：Simscape https://cn.mathworks.com/products/simscape.html\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.4 工业软件之中兴事件\n",
    "\n",
    "2018年4月16日晚，美国商务部发布公告称，美国政府在未来7年内禁止中兴通讯向美国企业购买敏感产品。\n",
    "\n",
    "EDA(Electronics Design Automation)软件是工业软件的尖端，代表了一个国家真正的研发创新，没有EDA软件的支持，再先进的芯片也会变成硅土。\n",
    "\n",
    "电子电路设计领域里世界上三大EDA软件是Cadence、Mentor和Synopsys。这三个软件全都是美国的\n",
    "\n",
    "中国的芯片设计严重依赖西方国家开发的EDA软件."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.5 Object-Oriented Modeling\n",
    "\n",
    "The software design methodology of object-oriented programming can be applied to systems modeling as well, with the benefits of simplified model creation and maintenance.\n",
    "\n",
    "**Object oriented model design** results in a hierarchical organization of models and simplifies the tasks of \n",
    "\n",
    "* **reusing, maintaining,and extending families of simulation model**s. \n",
    "\n",
    "Several research groups have developed **object-oriented languages** for discrete event systems as well as continuous systems.\n",
    "\n",
    "Not all these languages support the object-oriented paradigm to the same extent; \n",
    "\n",
    "* the most comprehensive support for object-oriented principles is contained in [Modelica](./Unit4-3-Modelica.ipynb)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2 An ideal vapor-compression refrigeration cycle\n",
    "\n",
    "* https://www.cpp.edu/~tknguyen/che302/home.htm\n",
    "\n",
    "  * https://www.cpp.edu/~tknguyen/che302/Notes/chap7-2.pdf\n",
    "  \n",
    "###  Example 7.2-3\n",
    "\n",
    "Refrigerant 134a is the working fluid in an ideal vapor-compression refrigeration cycle that\n",
    "communicates thermally with a cold region at 0°C and a warm region at 26°C. \n",
    "\n",
    "Saturated vapor enters the compressor at 0°C and saturated liquid leaves the condenser at 26°C.\n",
    "\n",
    "Themass flow rate of the refrigerant is 0.08 kg/s.\n",
    "\n",
    "\n",
    "![](./img/vcr/ivcr-example723.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Example 7.2-4\n",
    "\n",
    "Refrigerant 134a is the working fluid in an ideal vapor-compression refrigeration cycle that communicates thermally with a cold region at - 10°C.\n",
    "\n",
    "Saturated vapor enters the compressor at - 10°C and saturated liquid leaves the condenser at 9 bar.\n",
    "\n",
    "The mass flow rate of the refrigerant is 0.08 kg/s.\n",
    "\n",
    "\n",
    "![](./img/vcr/ivcr-example724.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Determine \n",
    "\n",
    "* (a) the compressor power, in kW,\n",
    "\n",
    "$$\\dot{W}_{c}=\\dot{m}*(h_2-h_1)$$\n",
    "\n",
    "* (b) the refrigeration capacity, in tons, \n",
    "\n",
    "$$\\dot{Q}_{L}=\\dot{m}*(h_1-h_4)*(60s/min)\\frac{1ton}{211 kJ/min}$$\n",
    "\n",
    "* (c) the coefficient of performance \n",
    "\n",
    "$$\\beta=\\frac{\\dot{Q}_{L}}{\\dot{W}_{c}}=\\frac{h_1-h_4}{h_2-h_1}$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3 The Object-oriented Programming of Refrigeration cycle\n",
    "\n",
    " Modeling and Simulation of the Refrigeratione Cycle with Computational Thinking to the generic solutions\n",
    " \n",
    "The **SimVCCE** is the vapor-compression refrigeration cycle steady-state simulator for education. The educational simulator is available in Python, C++ and Modelica\n",
    "\n",
    "* Github: https://github.com/PySEE/SimVCCE\n",
    "\n",
    "   \n",
    "\n",
    "### 3.1 The Projects of Refrigeration Cycle with OOP\n",
    "\n",
    "Apply **abstraction** and **decomposition** to code the cycle 7.2-3&7.2-4 simulator\n",
    "\n",
    "![](./img/vcr/vcr-cycle.jpg)\n",
    "\n",
    "\n",
    "**Decomposition** : Decompose The ideal refrigeration cycle into parts ： `devices` and `port`\n",
    "\n",
    "**Abstraction**  : Define the classes of item in cycle : `data and methods`\n",
    "\n",
    "Because\n",
    "\n",
    "* the device of cycle have ports\n",
    "\n",
    "![](./img/vcr/vcc-evaporator.jpg)\n",
    "\n",
    "* the devices are connected through ports to the cycle\n",
    "\n",
    "![](./img/vcr/vcc-cycle.jpg)\n",
    "\n",
    "So,we have the two kind of objects:\n",
    "\n",
    "* **1** - Port \n",
    "\n",
    "* **2** - devices: Compressor， Condenser，Expansion Valve ， Evaporator\n",
    "\n",
    "\n",
    "**Algorithms** : \n",
    "\n",
    "* connecte the devices to cycle through the ports\n",
    "\n",
    "* obtain the solutions of the cycle"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Python Version\n",
    "\n",
    "* Local: `../../SimVCCE`(current working dir: `notebook`)\n",
    "\n",
    "```\n",
    "<PySEE>\n",
    "   | \n",
    "   |─ <home>\n",
    "   |   |   \n",
    "   |   |─<notebook>\n",
    "   |     \n",
    "   |─ <SimVCCE>\n",
    "      |   \n",
    "      |─<vccpython> \n",
    "```     \n",
    "\n",
    "set `../../SimVCCE/vccpython` as the working dir"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%cd ../../SimVCCE/vccpython"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%pwd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!dir"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "```\n",
    "<vccpython>\n",
    "   | \n",
    "   |── vccapp.py  #  main app\n",
    "   |\n",
    "   |── <components> port and devices classes\n",
    "   |      |   \n",
    "   |      |── port.py\n",
    "   |      |── connector.py\n",
    "   |      |── compressor.py\n",
    "   |           .... \n",
    "   |── <vcc> cycle analysis methods\n",
    "   |      |\n",
    "   |      |── vccobj.py # the object of cycle \n",
    "   |      |     \n",
    "   |      |── utils.py #  utils methods  \n",
    "   |              \n",
    "   |── <vccmodel> the cycle data dicts\n",
    "   |      |\n",
    "   |      |── *vcr*.py # the cycle dict\n",
    "   |\n",
    "   |── <result>          \n",
    "         |\n",
    "         |─ *vcr*.txt \n",
    "         |  \n",
    "```         \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 Components Package\n",
    "\n",
    "./components/\n",
    "\n",
    "* `__init__.py`\n",
    "\n",
    "* port.py\n",
    "\n",
    "* compressor.py\n",
    "\n",
    "* condenser.py\n",
    "\n",
    "* expansionvalve.py\n",
    "\n",
    "* evaporator.py\n",
    "\n",
    "* connector.py\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.2.1 `__init__.py`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load ./components/__init__.py\n",
    "\"\"\"\n",
    "    Components Package  \n",
    "\"\"\"\n",
    "\n",
    "from .port import Port\n",
    "from .connector import Connector\n",
    "from .compressor import Compressor\n",
    "from .condenser import Condenser\n",
    "from .expansionvalve import ExpansionValve\n",
    "from .evaporator import Evaporator\n",
    "\n",
    "\n",
    "# ------------------------------------------------------------------------------\n",
    "# compdict(jump table)\n",
    "#  1: key:value-> Type String: class  name\n",
    "#  2    add the new key:value to the dict after you add the new device class/type\n",
    "# --------------------------------------------------------------------------------\n",
    "\n",
    "compdict = {\n",
    "    \"COMPRESSOR\": Compressor,\n",
    "    \"CONDENSER\": Condenser,\n",
    "    \"EXPANSIONVALVE\": ExpansionValve,\n",
    "    \"EVAPORATOR\": Evaporator\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.2.2 Port Class\n",
    "\n",
    "<b style=\"color:blue\">Port: dictnode dict</b>\n",
    "```\n",
    "{\"p\": None, \"t\": 0,  \"x\": 1, \"mdot\": 0.08}\n",
    "```\n",
    " \n",
    "* **Properties:** index, p,t,h,s,x,mdot,stateok \n",
    "\n",
    "* **Methods:** (p,t),(p,x),(t,x),(p,s),(p,h),state, `__str__`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load ./components/port.py\n",
    "\"\"\"\n",
    " The port of device\n",
    "\"\"\"\n",
    "import CoolProp.CoolProp as cp\n",
    "\n",
    "\n",
    "class Port:\n",
    "\n",
    "    title = ('{:^6} \\t{:<8} \\t{:>8} \\t{:>10} \\t{:>10} \\t{:^10} \\t{:>10}'.format\n",
    "             (\"Index\", \"P(MPa)\", \"T(°C)\", \"H(kJ/kg)\", \"S(kJ/kg.K)\",  \"Quality\", \"MDOT(kg/s)\"))\n",
    "\n",
    "    def __init__(self, dictport):\n",
    "        \"\"\" create the port object\"\"\"\n",
    "        self.index = None\n",
    "        self.p = None\n",
    "        self.t = None\n",
    "        self.x = None\n",
    "        self.mdot = None\n",
    "\n",
    "        if('p' in dictport):\n",
    "            try:\n",
    "                self.p = float(dictport['p'])\n",
    "            except:\n",
    "                pass\n",
    "\n",
    "        if ('t' in dictport):\n",
    "            try:\n",
    "                self.t = float(dictport['t'])\n",
    "            except:\n",
    "                pass\n",
    "\n",
    "        if ('x' in dictport):\n",
    "            try:\n",
    "                self.x = float(dictport['x'])\n",
    "            except:\n",
    "                pass\n",
    "\n",
    "        if ('mdot' in dictport):\n",
    "            try:\n",
    "                self.mdot = float(dictport['mdot'])\n",
    "            except:\n",
    "                pass\n",
    "\n",
    "        self.h = None\n",
    "        self.s = None\n",
    "        self.stateok = False\n",
    "\n",
    "        if self.t is not None and self.x is not None:\n",
    "            self.tx()\n",
    "        elif self.p is not None and self.x is not None:\n",
    "            self.px()\n",
    "        elif self.p is not None and self.t is not None:\n",
    "            self.pt()\n",
    "\n",
    "    def tx(self):\n",
    "        try:\n",
    "            self.p = cp.PropsSI('P', 'T', 273.15+self.t,\n",
    "                                'Q', self.x, 'R134a')/1.0e6\n",
    "            self.h = cp.PropsSI('H', 'T', 273.15+self.t,\n",
    "                                'Q', self.x, 'R134a')/1000\n",
    "            self.s = cp.PropsSI('S', 'T', 273.15+self.t,\n",
    "                                'Q', self.x, 'R134a')/1000\n",
    "            self.stateok = True\n",
    "        except:\n",
    "            self.stateok = False\n",
    "\n",
    "    def px(self):\n",
    "        try:\n",
    "            self.t = cp.PropsSI('T', 'P', self.p*1.0e6,\n",
    "                                'Q', self.x, 'R134a')-273.15\n",
    "            self.h = cp.PropsSI('H', 'P', self.p*1.0e6,\n",
    "                                'Q', self.x, 'R134a')/1000\n",
    "            self.s = cp.PropsSI('S', 'P', self.p*1.0e6,\n",
    "                                'Q', self.x, 'R134a')/1000\n",
    "            self.stateok = True\n",
    "        except:\n",
    "            self.stateok = False\n",
    "\n",
    "    def pt(self):\n",
    "        try:\n",
    "            self.h = cp.PropsSI('H', 'P', self.p*1.0e6, 'T',\n",
    "                                self.t+273.15, 'R134a')/1000\n",
    "            self.s = cp.PropsSI('S', 'P', self.p*1.0e6, 'T',\n",
    "                                self.t+273.15, 'R134a')/1000\n",
    "            self.x = cp.PropsSI('Q', 'P', self.p*1.0e6,\n",
    "                                'H', self.h*1000, 'R134a')\n",
    "            if self.x == -1:\n",
    "                self.x = None\n",
    "            self.stateok = True\n",
    "        except:\n",
    "            self.stateok = False\n",
    "\n",
    "    def ps(self):\n",
    "        try:\n",
    "            if self.h is None:\n",
    "                self.h = cp.PropsSI('H', 'P', self.p*1.0e6, 'S',\n",
    "                                    self.s*1000, 'R134a')/1000\n",
    "            if self.t is None:\n",
    "                self.t = cp.PropsSI('T', 'P', self.p*1.0e6, 'S',\n",
    "                                    self.s*1000, 'R134a')-273.15\n",
    "            if self.x is None:\n",
    "                self.x = cp.PropsSI('Q', 'P', self.p*1.0e6, 'S',\n",
    "                                    self.s*1000, 'R134a')\n",
    "                if self.x == -1:\n",
    "                    self.x = None\n",
    "            self.stateok = True\n",
    "        except:\n",
    "            self.stateok = False\n",
    "\n",
    "    def ph(self):\n",
    "        try:\n",
    "            if self.s is None:\n",
    "                self.s = cp.PropsSI('S', 'P', self.p*1.0e6, 'H',\n",
    "                                    self.h*1000, 'R134a')/1000\n",
    "            if self.t is None:\n",
    "                self.t = cp.PropsSI('T', 'P', self.p*1.0e6, 'H',\n",
    "                                    self.h*1000, 'R134a')-273.15\n",
    "            if self.x is None:\n",
    "                self.x = cp.PropsSI('Q', 'P', self.p*1.0e6, 'H',\n",
    "                                    self.h*1000, 'R134a')\n",
    "                if self.x == -1:\n",
    "                    self.x = None\n",
    "            self.stateok = True\n",
    "        except:\n",
    "            self.stateok = False\n",
    "\n",
    "    def state(self):\n",
    "        if self.stateok == False:\n",
    "            if self.p is not None and self.s is not None:\n",
    "                self.ps()\n",
    "            elif self.p is not None and self.h is not None:\n",
    "                self.ph()\n",
    "            elif self.p is not None and self.t is not None:\n",
    "                self.pt()\n",
    "\n",
    "    def __str__(self):\n",
    "        result = '{:^6}'.format(self.index)\n",
    "        OutStrs = [{\"fstr\": '\\t{:>7.4}', 'prop': self.p, \"sstr\": '\\t{:>7}'},\n",
    "                   {\"fstr\": '\\t{:>8.2f}', 'prop': self.t, \"sstr\": '\\t{:>8}'},\n",
    "                   {\"fstr\": '\\t{:>10.2f}', 'prop': self.h, \"sstr\": '\\t{:>10}'},\n",
    "                   {\"fstr\": '\\t{:>8.3f}',  'prop': self.s, \"sstr\": '\\t{:>8}'},\n",
    "                   {\"fstr\": '\\t{:>10.4f}', 'prop': self.x, \"sstr\": '\\t{:>10}'},\n",
    "                   {\"fstr\": '\\t{:>8.2f}',  'prop': self.mdot, \"sstr\": '\\t{:>8}'}\n",
    "                   ]\n",
    "\n",
    "        for item in OutStrs:\n",
    "            try:\n",
    "                result += item[\"fstr\"].format(item[\"prop\"])\n",
    "            except:\n",
    "                result += item[\"sstr\"].format(\"\")\n",
    "\n",
    "        return result\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### The alternative  design: ` __init__`\n",
    "\n",
    "* The dict `update`  \n",
    "\n",
    "* The  class attribute `__dict__`\n",
    "\n",
    "\n",
    "In Python Dictionary, `update ()` method updates the dictionary with the elements from the another dictionary object or from an iterable of key/value pairs. Syntax: `dict.update([other])`\n",
    "\n",
    "A special attribute of every module is `__dict__`.  This is the dictionary containing the module’s symbol table.\n",
    "\n",
    "```python\n",
    "import CoolProp.CoolProp as cp\n",
    "class Port:\n",
    "    title = ('{:^6} \\t{:<8} \\t{:>8} \\t{:>10} \\t{:>10} \\t{:^10} \\t{:>10}'.format\n",
    "             (\"Index\", \"P(MPa)\", \"T(°C)\", \"H(kJ/kg)\", \"S(kJ/kg.K)\",  \"Quality\", \"MDOT(kg/s)\"))\n",
    "    kwargs = {'p': None, 't': None, 'x': None,\n",
    "              'h': None,  's': None, 'mdot': None}\n",
    "        \n",
    "    def __init__(self, dictnode):\n",
    "        \"\"\" create the port object\"\"\"\n",
    "        kwargs = Port.kwargs.copy()\n",
    "        kwargs.update(dictnode)\n",
    "       \n",
    "        for key in Port.kwargs.keys():\n",
    "            if type(kwargs[key]) is int:\n",
    "                kwargs[key] = float(kwargs[key])\n",
    "        \n",
    "        self.__dict__.update(kwargs)\n",
    "        \n",
    "        self.index=None\n",
    "        self.stateok = False\n",
    "       \n",
    "```            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Port:\n",
    "    kwargs = {'p': None,\n",
    "              't': None}\n",
    "    def __init__(self,dictNode):\n",
    "        kwargs = Port.kwargs.copy()\n",
    "        kwargs.update(dictNode)\n",
    "        \n",
    "        for key in Port.kwargs.keys():\n",
    "            if type(kwargs[key]) is int:\n",
    "                kwargs[key] = float(kwargs[key])\n",
    "        \n",
    "        self.__dict__.update(kwargs)\n",
    "\n",
    "dictNode={\"p\":100}        \n",
    "d1=Port(dictNode)\n",
    "print(d1.p)\n",
    "print(d1.t)\n",
    "dictNode={\"p\":100,\"t\":20.0}        \n",
    "d2=Port(dictNode)\n",
    "print(d2.p)\n",
    "print(d2.t)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.2.3 Device Classes\n",
    "\n",
    "<b style=\"color:blue\">dictDev</b>\n",
    "\n",
    "```python\n",
    "  {\n",
    "        \"name\": \"Compressor\",\n",
    "        \"devtype\": \"COMPRESSOR\",\n",
    "        \"iPort\": {\"t\": 0,  \"x\": 1, \"mdot\": 0.08},\n",
    "        \"oPort\": {},\n",
    "        \"ef\": 1.0\n",
    "    }\n",
    "```\n",
    "\n",
    "The device classe have\n",
    "\n",
    "**Properties**: \n",
    " \n",
    "* name = dictDev['name']\n",
    "\n",
    "* iPort = [Port(dictDev['iPort'])]\n",
    "* oPort = [Port(dictDev['oPort'])]\n",
    "* portdict：map the name of port to the port obj\n",
    "```python \n",
    " portdict = {\n",
    "            \"iPort\": self.iPort,\n",
    "            \"oPort\": self.oPort\n",
    "        }\n",
    "```  \n",
    "\n",
    ">**Port is the list with one item** : `[Port(dictDev['iPort'])]` (list is mutable!)\n",
    "\n",
    "\n",
    "**Methods**\n",
    "\n",
    "* state(self)\n",
    "   \n",
    "* balance(self)\n",
    "   \n",
    "* `__str__(self)`\n",
    "\n",
    "For example:\n",
    "\n",
    "```python\n",
    "class Compressor:\n",
    "    energy = \"CompressionWork\"\n",
    "    devtype = \"COMPRESSOR\"\n",
    "\n",
    "    def __init__(self, dictDev):\n",
    "        self.name = dictDev['name']\n",
    "        self.iPort = [Port(dictDev['iPort'])]\n",
    "        self.oPort = [Port(dictDev['oPort'])]\n",
    "        # map the name of port to the port obj\n",
    "        self.portdict = {\n",
    "            \"iPort\": self.iPort,\n",
    "            \"oPort\": self.oPort\n",
    "        }\n",
    "   \n",
    "    def state(self):\n",
    "   \n",
    "    def balance(self):\n",
    "   \n",
    "    def __str__(self):\n",
    "```\n",
    " \n",
    "#####  1) Compressor Class:\n",
    "\n",
    "![](./img/vcr/vcr-compressor.jpg)\n",
    "\n",
    "* **Properties:**  \n",
    " \n",
    "  * iPort，oPort,...\n",
    "  \n",
    "  * compressor work\n",
    "\n",
    "* **Process:**  \n",
    "  \n",
    "  * Isentropic compression(ideal VPR cycle)\n",
    "\n",
    "**Port is the list with one item**\n",
    "\n",
    "* self.iPort = [Port(dictDev['iPort'])]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%load ./components/compressor.py\n",
    "\n",
    "from .port import *\n",
    "import CoolProp.CoolProp as cp\n",
    "\n",
    "\n",
    "class Compressor:\n",
    "    \"\"\" compression of the refrigerant\"\"\"\n",
    "    energy = \"CompressionWork\"\n",
    "    devtype = \"COMPRESSOR\"\n",
    "\n",
    "    def __init__(self, dictDev):\n",
    "        \"\"\"\n",
    "        Initializes \n",
    "        \"\"\"\n",
    "        self.name = dictDev['name']\n",
    "        self.iPort = [Port(dictDev['iPort'])]\n",
    "        self.oPort = [Port(dictDev['oPort'])]\n",
    "        try:\n",
    "            self.ef = float(dictDev['ef'])\n",
    "        except:\n",
    "            self.ef = None\n",
    "\n",
    "        self.Wc = None\n",
    "        # map the name of port to the port obj\n",
    "        self.portdict = {\n",
    "            \"iPort\": self.iPort,\n",
    "            \"oPort\": self.oPort\n",
    "        }\n",
    "\n",
    "    def state(self):\n",
    "        \"\"\"\n",
    "        compression of the refrigeran\n",
    "        \"\"\"\n",
    "        if self.ef == 1.0:\n",
    "            self.oPort[0].s = self.iPort[0].s\n",
    "        self.isos = self.iPort[0].s\n",
    "\n",
    "    def balance(self):\n",
    "        \"\"\"  mass and energy balance    \"\"\"\n",
    "        # mass balance\n",
    "        if self.iPort[0].mdot is not None:\n",
    "            self.oPort[0].mdot = self.iPort[0].mdot\n",
    "        elif self.oPort[0].mdot is not None:\n",
    "            self.iPort[0].mdot = self.oPort[0].mdot\n",
    "        # energy\n",
    "        if self.ef != 1.0 or self.ef is None:\n",
    "            self.isoh = cp.PropsSI('H', 'P', self.oPort[0].p*1.0e6, 'S',\n",
    "                                   self.isos*1000, 'R134a')/1000\n",
    "            if self.ef is None:\n",
    "                self.ef = (self.isoh-self.iPort[0].h) / \\\n",
    "                    (self.oPort[0].h-self.iPort[0].h)\n",
    "            elif self.ef < 1.0 and self.ef > 0.0:\n",
    "                self.oPort[0].h = (\n",
    "                    self.isoh-self.iPort[0].h)/self.ef + self.iPort[0].h\n",
    "                self.oPort[0].state()\n",
    "        # wc\n",
    "        self.Wc = self.iPort[0].mdot * (self.oPort[0].h - self.iPort[0].h)\n",
    "\n",
    "    def __str__(self):\n",
    "        result = '\\n' + self.name\n",
    "        result += '\\n' +\" PORTS \"+Port.title\n",
    "        result += '\\n' +\" iPort \"+ self.iPort[0].__str__()\n",
    "        result += '\\n' +\" oPort \"+ self.oPort[0].__str__()\n",
    "        try:\n",
    "            result += '\\nThe compressor efficiency(%): \\t{:>.2f}'.format(\n",
    "                self.ef*100.0)\n",
    "        except:\n",
    "            pass\n",
    "        result += '\\nWc(kW): \\t{:>.2f}'.format(self.Wc)\n",
    "        return result\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 2) Condenser Class\n",
    "\n",
    "The Condenser \n",
    "\n",
    "![](./img/vcr/vcr-condenser.jpg)\n",
    "\n",
    "* **Properties:**  \n",
    " \n",
    "  * iPort，oPort \n",
    "  \n",
    "* **Process** \n",
    "\n",
    "  *  Isobaric heat rejection "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load ./components/condenser.py\n",
    "\n",
    "from .port import *\n",
    "import CoolProp.CoolProp as cp\n",
    "\n",
    "\n",
    "class Condenser:\n",
    "\n",
    "    energy = \"QOUT\"\n",
    "    devtype = \"CONDENSER\"\n",
    "\n",
    "    def __init__(self, dictDev):\n",
    "        \"\"\" Initializes the condenser \"\"\"\n",
    "        self.name = dictDev['name']\n",
    "        self.iPort = [Port(dictDev['iPort'])]\n",
    "        self.oPort = [Port(dictDev['oPort'])]\n",
    "        # map the name of port to the port obj\n",
    "        self.portdict = {\n",
    "            \"iPort\": self.iPort,\n",
    "            \"oPort\": self.oPort\n",
    "        }\n",
    "\n",
    "    def state(self):\n",
    "        self.iPort[0].p = self.oPort[0].p\n",
    "\n",
    "    def balance(self):\n",
    "        \"\"\" mass and energy balance of the condenser  \"\"\"\n",
    "        if self.iPort[0].mdot is not None:\n",
    "            self.oPort[0].mdot = self.iPort[0].mdot\n",
    "        elif self.oPort[0].mdot is not None:\n",
    "            self.iPort[0].mdot = self.oPort[0].mdot\n",
    "\n",
    "        self.Qout = self.iPort[0].mdot*(self.iPort[0].h-self.oPort[0].h)\n",
    "\n",
    "    def __str__(self):\n",
    "        result = '\\n' + self.name\n",
    "        result += '\\n' +\" PORTS \"+Port.title\n",
    "        result += '\\n' +\" iPort \"+ self.iPort[0].__str__()\n",
    "        result += '\\n' +\" oPort \"+ self.oPort[0].__str__()\n",
    "        result += '\\nQout(kW): \\t{:>.2f}'.format(self.Qout)\n",
    "        return result\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 3) Expansion Valve Class\n",
    "\n",
    "![](./img/vcr/vcr-expansionvalve.jpg)\n",
    "\n",
    "* **Properties:**  \n",
    " \n",
    "  * iPort，oPort\n",
    "  \n",
    "* **Process**\n",
    "  * Throttling : Isenthalpic expansion"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load ./components/expansionvalve.py\n",
    "from .port import *\n",
    "\n",
    "\n",
    "class ExpansionValve:\n",
    "\n",
    "    energy = \"None\"\n",
    "    devtype = \"EXPANSIONVALVE\"\n",
    "\n",
    "    def __init__(self, dictDev):\n",
    "        \"\"\" Initializes the ExpansionValve \"\"\"\n",
    "        self.name = dictDev['name']\n",
    "        self.iPort = [Port(dictDev['iPort'])]\n",
    "        self.oPort = [Port(dictDev['oPort'])]\n",
    "        # map the name of port to the port obj\n",
    "        self.portdict = {\n",
    "            \"iPort\": self.iPort,\n",
    "            \"oPort\": self.oPort\n",
    "        }\n",
    "\n",
    "    def state(self):\n",
    "        self.oPort[0].h = self.iPort[0].h\n",
    "\n",
    "    def balance(self):\n",
    "        \"\"\" mass and energy balance  \"\"\"\n",
    "        if self.iPort[0].mdot is not None:\n",
    "            self.oPort[0].mdot = self.iPort[0].mdot\n",
    "        elif self.oPort[0].mdot is not None:\n",
    "            self.iPort[0].mdot = self.oPort[0].mdot\n",
    "\n",
    "    def __str__(self):\n",
    "        result = '\\n' + self.name\n",
    "        result += '\\n' +\" PORTS \"+Port.title\n",
    "        result += '\\n' +\" iPort \"+ self.iPort[0].__str__()\n",
    "        result += '\\n' +\" oPort \"+ self.oPort[0].__str__()\n",
    "        return result\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 4) Evaporator Class\n",
    "\n",
    "The Evaporator \n",
    "\n",
    "![](./img/vcr/vcr-evaporator.jpg)\n",
    "`\n",
    "* **Properties:**  \n",
    " \n",
    "  * iPort，oPort \n",
    "  \n",
    "  * Qlow\n",
    "* **Process**\n",
    "  \n",
    "  * Constant pressure heat addition in the evaporator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load ./components/evaporator.py\n",
    "\n",
    "from .port import *\n",
    "\n",
    "\n",
    "class Evaporator:\n",
    "\n",
    "    energy = \"QIN\"\n",
    "    devtype = \"EVAPORATOR\"\n",
    "\n",
    "    def __init__(self, dictDev):\n",
    "        \"\"\" Initializes the Evaporator \"\"\"\n",
    "        self.name = dictDev['name']\n",
    "        self.iPort = [Port(dictDev['iPort'])]\n",
    "        self.oPort = [Port(dictDev['oPort'])]\n",
    "        # map the name of port to the port obj\n",
    "        self.portdict = {\n",
    "            \"iPort\": self.iPort,\n",
    "            \"oPort\": self.oPort\n",
    "        }\n",
    "\n",
    "    def state(self):\n",
    "        self.iPort[0].p = self.oPort[0].p\n",
    "\n",
    "    def balance(self):\n",
    "        \"\"\" mass and energy balance  \"\"\"\n",
    "        if self.iPort[0].mdot is not None:\n",
    "            self.oPort[0].mdot = self.iPort[0].mdot\n",
    "        elif self.oPort[0].mdot is not None:\n",
    "            self.iPort[0].mdot = self.oPort[0].mdot\n",
    "        self.Qin = self.iPort[0].mdot * (self.oPort[0].h - self.iPort[0].h)\n",
    "\n",
    "    def __str__(self):\n",
    "        result = '\\n' + self.name\n",
    "        result += '\\n' + \" PORTS \"+Port.title\n",
    "        result += '\\n' + \" iPort \" + self.iPort[0].__str__()\n",
    "        result += '\\n' + \" oPort \" + self.oPort[0].__str__()\n",
    "        result += '\\nQin(kW): \\t{:>.2f}'.format(self.Qin)\n",
    "        return result\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.2.4 Connector \n",
    "\n",
    "<b style=\"color:blue\">Connector variable of deivces is `tuple in the tuple` of device port()</b>\n",
    "\n",
    "* the connector tuple：`(compA_port,compB_port）`\n",
    "\n",
    "* the device `comp*_port` tuple：`(classname,portname)`\n",
    "\n",
    "For example:\n",
    "\n",
    "```python\n",
    "((\"Compressor\", \"oPort\"), (\"Condenser\", \"iPort\")),\n",
    "```\n",
    "\n",
    "**Properties**\n",
    "\n",
    "* nodes=[] : node: `(compA_port,compB_port）`\n",
    "* curindex=0 :  the index of new node \n",
    "        \n",
    "**Methods:**\n",
    "\n",
    "*  combined_node_value(self, node, port)\n",
    "\n",
    "*  add_node(self, tupConnector,comps)\n",
    "\n",
    "**Every Port of the device is the list with a port instance**\n",
    "\n",
    "* [the port instance ] \n",
    "\n",
    "```python\n",
    "self.iPort = [Port(dictDev['iPort'])]\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load ./components/connector.py\n",
    "\"\"\"\n",
    "\n",
    "class Connector\n",
    "\n",
    "\"\"\"\n",
    "\n",
    "from .port import *\n",
    "\n",
    "class Connector:\n",
    "\n",
    "    def __init__(self):\n",
    "        self.nodes=[]\n",
    "        self.curindex=0\n",
    "       \n",
    "    def combined_node_value(self, node, port):\n",
    "        \"\"\" \n",
    "           the node is the connector of two ports ,so the node may get values from all of two ports\n",
    "            the values is the union set of the non-none values within two ports \n",
    "        \"\"\"\n",
    "        for key in node[0].__dict__.keys():\n",
    "            nodevalue = getattr(node[0], key)\n",
    "            portvalue = getattr(port[0], key)\n",
    "            if nodevalue is None and portvalue is not None:\n",
    "               setattr(node[0], key, portvalue)\n",
    "   \n",
    "    def add_node(self, tupConnector,comps):\n",
    "        \"\"\" node : ((\"comp0\", \"port0\"), (\"comp1\", \"port1\")\"\"\"\n",
    "        comp0, port0 =tupConnector[0] \n",
    "        comp1, port1 =tupConnector[1]\n",
    "        \n",
    "        # 1 get the port [] list: list is mutable!\n",
    "        comp_port0 = comps[comp0].portdict[port0]\n",
    "        comp_port1 = comps[comp1].portdict[port1]\n",
    "\n",
    "        # 2 get the index of port in nodes\n",
    "        comp_port0[0].index = self.curindex\n",
    "        \n",
    "        # 3 create the new node with comp_port0 \n",
    "        self.nodes.append(comp_port0)\n",
    "        \n",
    "        # 4 join comp_port1 info into  nodes[self.curindex]\n",
    "        curnode = self.nodes[self.curindex]\n",
    "        self.combined_node_value(curnode, comp_port1)\n",
    "        # 5 set the pointer of comp_port1[0] to nodes[self.curindex][0]\n",
    "        comp_port1[0] = curnode[0]\n",
    "     \n",
    "        self.curindex += 1\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#####  The list is mutable\n",
    "\n",
    "\n",
    "In Python, a list is represented as a length (the number of objects in the list) and a sequence of fixed-size **pointers** to objects.\n",
    "\n",
    "The Figure  illustrates the use of these pointers. \n",
    "\n",
    "![](./img/python-list.png)\n",
    "\n",
    "The shaded region represents a list containing four elements. \n",
    "\n",
    "* The leftmost shaded box contains a pointer to an integer indicating the length of the list. \n",
    "\n",
    "*  <b style=\"color:blue\">Each of the other shaded boxes contains a `pointer` to an object in the list<b>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### The built-in class attribute `__dict__`\n",
    "\n",
    "A special attribute of every module is `__dict__`. \n",
    "\n",
    "`instancevariables.__dict__`\n",
    "\n",
    "* The `dictionary` containing instance variables"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'name': 'kitty', 'age': 5}\n",
      "dict_keys(['name', 'age'])\n",
      "{'name': None, 'age': None}\n",
      "dict_keys(['name', 'age'])\n"
     ]
    }
   ],
   "source": [
    "class cat:\n",
    "    def __init__(self, name=None,age=None):\n",
    "        self.name = name\n",
    "        self.age=age\n",
    "\n",
    "c=cat(\"kitty\",5)\n",
    "print(c.__dict__)\n",
    "print(c.__dict__.keys())\n",
    "d=cat()\n",
    "print(d.__dict__)\n",
    "print(d.__dict__.keys())\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### The `getattr(), setattr()` Built-in Functions\n",
    "\n",
    "\n",
    "```getattr(object_name, attr_nname)```\n",
    "\n",
    "  * returns the value of the attr_name of the obj_name, equivalent to `obj_name.attr_name`.\n",
    "\n",
    "\n",
    "```setattr(obj_name, attr_name, attr_value)```\n",
    "\n",
    "* sets a value to the attribute, equivalent to `obj_name.attr_name =attr_value`\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "set c to d\n",
      "{'name': 'kitty', 'age': 5}\n"
     ]
    }
   ],
   "source": [
    "# set c to d \n",
    "print(\"set c to d\")\n",
    "for key in c.__dict__.keys():\n",
    "    setattr(d, key, getattr(c, key))\n",
    "print(d.__dict__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.3 Cyclemodel Package  \n",
    "\n",
    "cycle data\n",
    "\n",
    "```python\n",
    "cycle = {}\n",
    "cycle[\"name\"] = \"The Ideal VCR Example 7.2-3\"\n",
    "cycle[\"components\"] = [devices dict]\n",
    "cycle[\"connectors\"] = [connector tuple]\n",
    "```\n",
    "./vccmodel/\n",
    "\n",
    "* `__init__.py`\n",
    "\n",
    "* ivcr723.py\n",
    "\n",
    "* ivcr724.py\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load ./vccmodel/__init__.py\n",
    "from . import ivcr723\n",
    "from . import ivcr724\n",
    "\n",
    "cycles = [ivcr723,ivcr724]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load ./vccmodel/ivcr723.py\n",
    "cycle = {}\n",
    "cycle[\"name\"] = \"The Ideal VCR Example 7.2-3\"\n",
    "cycle[\"components\"] = [\n",
    "    {\n",
    "        \"name\": \"Compressor\",\n",
    "        \"devtype\": \"COMPRESSOR\",\n",
    "        \"iPort\": {\"t\": 0,  \"x\": 1, \"mdot\": 0.08},\n",
    "        \"oPort\": {},\n",
    "        \"ef\": 1.0\n",
    "    },\n",
    "    {\n",
    "        \"name\": \"Condenser\",\n",
    "        \"devtype\": \"CONDENSER\",\n",
    "        \"iPort\": {},\n",
    "        \"oPort\": {\"t\": 26,  \"x\": 0},\n",
    "\n",
    "    },\n",
    "    {\n",
    "        \"name\": \"ExpansionValve\",\n",
    "        \"devtype\": \"EXPANSIONVALVE\",\n",
    "        \"iPort\": {},\n",
    "        \"oPort\": {},\n",
    "    },\n",
    "    {\n",
    "        \"name\": \"Evaporator\",\n",
    "        \"devtype\": \"EVAPORATOR\",\n",
    "        \"iPort\": {},\n",
    "        \"oPort\": {},\n",
    "    }\n",
    "]\n",
    "\n",
    "cycle[\"connectors\"] = [\n",
    "    ((\"Compressor\", \"oPort\"), (\"Condenser\", \"iPort\")),\n",
    "    ((\"Condenser\", \"oPort\"), (\"ExpansionValve\", \"iPort\")),\n",
    "    ((\"ExpansionValve\", \"oPort\"), (\"Evaporator\", \"iPort\")),\n",
    "    ((\"Evaporator\", \"oPort\"), (\"Compressor\", \"iPort\"))]\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.4 vcc  Package\n",
    "\n",
    " \n",
    "#### 3.4.1 The Flowchart  \n",
    "\n",
    "  \n",
    "* 1 init device,connector \n",
    "\n",
    "* 2 simulate devices\n",
    "  \n",
    " * 2.1 port state of device\n",
    "\n",
    " * 2.2 mass and energy balance of device \n",
    "\n",
    "* 3 cycle performance\n",
    "\n",
    "![](./img/vcr/pyvcr-flowchart.jpg)\n",
    "\n",
    "\n",
    "Analysis the Refrigeration  Cycle \n",
    "\n",
    " ./vcc/\n",
    " \n",
    " * `__init__.py`\n",
    " \n",
    " * vccobj.py\n",
    " \n",
    " * utils.py\n",
    " \n",
    "#### 3.4.1  `__init__.py`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load ./vcc/__init__.py\n",
    "\n",
    "\"\"\"\n",
    " General Object-oriented Abstraction of vc Cycle \n",
    "    \n",
    "    cycle Package \n",
    "\n",
    "\"\"\"\n",
    "\n",
    "import sys\n",
    "sys.path.append('../')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.4.2 cycleobj.py\n",
    "\n",
    "```python\n",
    "  dictcycle={\"type\":typestring,\n",
    "         \"name\":namestring,\n",
    "         \"components\":[{component1},{component2},...],\n",
    "         \"connectors\":[((name1,port1),(name2,port2)),...]\n",
    "         }\n",
    "  TO:     \n",
    "     self.comps : dict of all component objects      \n",
    "     self.conns : the connector object\n",
    "```\n",
    "**Sequential-modular approach(SM 序贯模块法)**\n",
    "\n",
    "* Process units are solved in sequence, starting with the feed streams.\n",
    "\n",
    "```python\n",
    "def ComponentBalance(self):\n",
    "        for curdev in self.comps:\n",
    "            self.comps[curdev].balance()\n",
    "```            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load ./vcc/vccobj.py\n",
    "\"\"\"\n",
    " General Object-oriented Abstraction of vcr Cycle \n",
    "\n",
    "RefrigerationCycle: the Simulator class of VCR Cycle  \n",
    "\n",
    "\n",
    "\"\"\"\n",
    "\n",
    "import time\n",
    "from platform import os\n",
    "import getpass\n",
    "\n",
    "from components.port import Port\n",
    "from components.connector import Connector\n",
    "from components import compdict\n",
    "\n",
    "\n",
    "class VCCycle:\n",
    "\n",
    "    def __init__(self, dictcycle):\n",
    "        \"\"\"\n",
    "          dictcycle={\"name\":namestring,\n",
    "                     \"components\":[{component1},{component2},...],\n",
    "                     \"connectors\":[((name1,port1),(name2,port2)),...]\n",
    "                  }\n",
    "          TO:     \n",
    "             self.comps : dict of all component objects      \n",
    "             self.conns : the connector object\n",
    "        \"\"\"\n",
    "        self.name = dictcycle[\"name\"]\n",
    "        dictcomps = dictcycle[\"components\"]\n",
    "        listconnectors = dictcycle[\"connectors\"]\n",
    "\n",
    "        # 1 convert dict to the dict of device objects: {device name:device obiect}\n",
    "        self.DevNum = len(dictcomps)\n",
    "        self.comps = {}\n",
    "        for curdev in dictcomps:\n",
    "            self.comps[curdev['name']] = compdict[curdev['devtype']](curdev)\n",
    "\n",
    "        self.conns = Connector()\n",
    "        # 2 use the dictconnectors to set the nodes value and alias between the item of nodes and the port of devices\n",
    "        for tupconnector in listconnectors:\n",
    "            self.conns.add_node(tupconnector, self.comps)\n",
    "\n",
    "        self.Wc = None\n",
    "        self.Qlow =None\n",
    "        self.cop = None\n",
    "\n",
    "    def ComponentState(self):\n",
    "        \"\"\" calculate the state of ports \"\"\"\n",
    "        # the ports state of devices\n",
    "        for key in self.comps:\n",
    "            self.comps[key].state()\n",
    "\n",
    "        # the nodes state of connectors\n",
    "        for item in self.conns.nodes:\n",
    "            if item[0].stateok == False:\n",
    "                item[0].state()\n",
    "\n",
    "    def ComponentBalance(self):\n",
    "        for curdev in self.comps:\n",
    "            self.comps[curdev].balance()\n",
    "\n",
    "    def simulator(self):\n",
    "        self.ComponentState()\n",
    "        self.ComponentBalance()\n",
    "\n",
    "        self.Wc = 0\n",
    "        self.Qin = 0\n",
    "        self.Qout = 0\n",
    "\n",
    "        for key in self.comps:\n",
    "            if self.comps[key].energy == \"CompressionWork\":\n",
    "                self.Wc += self.comps[key].Wc\n",
    "            elif self.comps[key].energy == \"QIN\":\n",
    "                self.Qin += self.comps[key].Qin\n",
    "\n",
    "        self.cop = self.Qin / self.Wc\n",
    "        self.Qin = self.Qin*60*(1/211)\n",
    "\n",
    "    def __setformatstr(self, formatstr, result):\n",
    "        result += formatstr.format('Compression Work(kW): ', self.Wc)\n",
    "        result += formatstr.format('Refrigeration Capacity(ton): ', self.Qin)\n",
    "        result += formatstr.format('The coefficient of performance: ', self.cop)\n",
    "        return result\n",
    "\n",
    "    def __str__(self):\n",
    "        str_curtime = time.strftime(\n",
    "            \"%Y/%m/%d %H:%M:%S\", time.localtime(time.time()))\n",
    "        result = \"\\nRefrigeration Cycle: {} (Time: {} by {} on {})\\n\".format(\n",
    "            self.name, str_curtime, getpass.getuser(), os.popen('hostname').read())\n",
    "        try:\n",
    "            formatstr = \"{:>35} {:>5.2f}\\n\"\n",
    "            result = self.__setformatstr(formatstr, result)\n",
    "        except:\n",
    "            formatstr = \"{} {}\\n\"\n",
    "            result = self.__setformatstr(formatstr, result)\n",
    "        return result\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#####   ComponentState method:\n",
    "\n",
    "The thermophysical property: **`Two` Sources of Physical Property calculation**\n",
    "\n",
    "1. Port's known parameter pairs\n",
    "2. Component's thermodynamic process**\n",
    "\n",
    "#####  1. Port's known parameter pairs\n",
    "\n",
    "* `__init__`:  the port's known parameter pairs in the  instantiating port\n",
    "\n",
    "* `state(self)`: update the parameter pairs of port by the component's thermodynamic process\n",
    "\n",
    "\n",
    "```python\n",
    "class Port:\n",
    "    \n",
    "def __init__(self, dictnode):\n",
    "        \"\"\" create the node object\"\"\"\n",
    "        if self.t is not None and self.x is not None:\n",
    "            self.tx()\n",
    "        elif self.p is not None and self.x is not None:\n",
    "            self.px()\n",
    "        elif self.p is not None and self.t is not None:\n",
    "            self.pt()\n",
    "\n",
    "```\n",
    "\n",
    " ```python\n",
    " def state(self):\n",
    "        if self.stateok == False:\n",
    "            if self.p is not None and self.s is not None:\n",
    "               self.ps()\n",
    "            elif self.p is not None and self.h is not None:\n",
    "               self.ph()\n",
    "            elif self.p is not None and self.t is not None:\n",
    "               self.pt()\n",
    "\n",
    "```\n",
    "\n",
    "##### 2. Component's thermodynamic process\n",
    "\n",
    "```python\n",
    "class Compressor:\n",
    "  \n",
    "    def state(self):\n",
    "        \"\"\"\n",
    "        Isentropic compression  (ideal VPR cycle)\n",
    "        \"\"\"\n",
    "        self.oNode.s = self.iNode.s\n",
    "```\n",
    "\n",
    "**Physical Property calculation methods**\n",
    "\n",
    "1. `Port(dictNode)` - port\n",
    "\n",
    "2. `comps[key].state()` - device\n",
    "\n",
    "3. `curcon.nodes[i].state()` - port\n",
    "\n",
    "\n",
    "```python\n",
    "class VCRCycle:\n",
    "    \n",
    "    def __init__(self, dictcycle):\n",
    "        self.DevNum = len(dictcomps)\n",
    "        self.comps = {}\n",
    "        for curdev in dictcomps:\n",
    "            self.comps[curdev['name']] = compdict[curdev['devtype']](curdev) # `Port(dictNode)` - port     \n",
    "    \n",
    "    def ComponentState(self):\n",
    "        \"\"\" calculate the state of ports \"\"\"\n",
    "        # the ports state oof devices\n",
    "        for key in self.comps:\n",
    "            self.comps[key].state()\n",
    "\n",
    "        # the nodes state oof connectors\n",
    "        for item in self.conns.nodes:\n",
    "            if item[0].stateok == False:\n",
    "                item[0].state()\n",
    " "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.4.3 utils.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load ./vcc/utils.py\n",
    "\"\"\"\n",
    "General Object-oriented Abstraction of vcr Cycle \n",
    "\n",
    " - OutFiles(cycle, outfilename=None)\n",
    "\n",
    "\"\"\"\n",
    "import sys\n",
    "from components.port import Port\n",
    "\n",
    "def OutFiles(cycle, outfilename=None):\n",
    "    savedStdout = sys.stdout\n",
    "    # redirect to the outfilename\n",
    "    if outfilename is not None:\n",
    "        datafile = open(outfilename, 'w', encoding='utf-8')\n",
    "        sys.stdout = datafile\n",
    "\n",
    "    # 1 output cycle performance\n",
    "    print(cycle)\n",
    "   \n",
    "    # 2 output nodes\n",
    "    print(Port.title)\n",
    "    for item in cycle.conns.nodes:\n",
    "        print(item[0])\n",
    "    # 3 output devices\n",
    "    for key in cycle.comps:\n",
    "        print(cycle.comps[key])\n",
    "    \n",
    "    # return to sys.stdout\n",
    "    if (outfilename != None):\n",
    "        datafile.close()\n",
    "        sys.stdout = savedStdout\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.5 Main\n",
    "\n",
    "* `./vccapp.py`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load ./vccapp.py\n",
    "\n",
    "\"\"\"\n",
    "General Object-oriented Abstraction  of VP Cycle \n",
    "\n",
    "The Simulator of VC Cycle \n",
    "  * Input :VC cycle dict model\n",
    "  * Output: text file\n",
    "Run: \n",
    "   python vccapp.py\n",
    "\"\"\"\n",
    "from vcc.vccobj import VCCycle\n",
    "from vcc.utils import OutFiles\n",
    "from vccmodel import cycles\n",
    "from platform import os\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "\n",
    "    curpath = os.path.abspath(os.path.dirname(__file__))\n",
    "    ResultFilePath = curpath+'/result/'\n",
    "\n",
    "    for curcycle in cycles:\n",
    "        ResultFileName = ResultFilePath+curcycle.cycle['name']\n",
    "\n",
    "        cycle = VCCycle(curcycle.cycle)\n",
    "        cycle.simulator()\n",
    "        # output to text\n",
    "        OutFiles(cycle)\n",
    "        OutFiles(cycle, ResultFileName + '.txt')\n",
    "\n",
    "      "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4 Computational Thinking(编程思维）\n",
    "\n",
    "Programming is about managing <b>complexity</b> in a way that <b>facilitates change</b>.\n",
    "\n",
    "There are **two** powerful mechanisms available for accomplishing this: \n",
    "\n",
    "* <b style=\"color:blue\">decomposition</b> \n",
    "\n",
    "* <b style=\"color:blue\">abstraction</b>`  \n",
    "\n",
    "Apply **abstraction** and **decomposition** to solve more complex problems\n",
    " \n",
    "* **decomposition**: decompose a <b style=\"color:blue\">large</b>` problem into <b style=\"color:blue\">parts</b> and design algorithms to solve them\n",
    "\n",
    "* **abstractions** recognise <b style=\"color:blue\">similar</b> problems,and apply <b style=\"color:blue\">generic` solutions</b>\n",
    "\n",
    "* creating **algorithms** to obtain the generic `solution`  results\n",
    "\n",
    "The set of problem-solving methods with computer is also called [Computational Thinking](https://en.wikipedia.org/wiki/Computational_thinking). \n",
    "\n",
    "The characteristics that define [Computational Thinking](https://en.wikipedia.org/wiki/Computational_thinking) are \n",
    "\n",
    "  * decomposition \n",
    "  * pattern recognition/data representation,\n",
    "  * generalization/abstraction,\n",
    "  * algorithms\n",
    "    \n",
    " ![](./img/ComputationalThinking.jpg)   \n",
    " \n",
    "<b style=\"color:blue\">Thinking computationally is a fundamental skill for everyone, not just computer scientists</b>\n",
    ">[Jeannette M. Wing, Computational Thinking Benefits Society](http://socialissues.cs.toronto.edu/index.html%3Fp=279.html)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.7"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "223px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  },
  "widgets": {
   "state": {},
   "version": "1.1.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
